package org.demo;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewConstructor;
import javassist.CtNewMethod;
import javassist.NotFoundException;
import javassist.bytecode.AccessFlag;

public class JavassitDemo {

	public static void main(String[] args)throws Exception {
		System.out.println(">>>>>>>>>>>>before");
		//testMethod(Point.class);
		System.out.println(">>>>>>>>>>>>change");
		changeMethod();
		System.out.println(">>>>>>>>>>>>after");
		testMethod(Point.class);
	}
	
	public static void changeMethod()throws Exception {
		ClassPool pool=ClassPool.getDefault();
        CtClass ct=pool.getCtClass("org.demo.Point");
        //类修改后,javassist会冻结这个CtClass对象,且
        if(ct.isFrozen()){
            ct.defrost();
        }
        CtMethod m=ct.getDeclaredMethod("move");
        m.insertBefore("{ System.out.print(\"dx:\"+$1); System.out.println(\"dy:\"+$2);}");
        ct.writeFile("I:\\gitWorkspace\\demo\\demo\\javassit-demo\\target\\newClasses");
        //通过反射调用方法，查看结果
        Class pc=ct.toClass();
        testMethod(pc);
	}
	
	public static void testMethod(Class<?> cl)throws Exception {
		Method move= cl.getMethod("move",new Class[]{int.class,int.class});
        Constructor<?> con=cl.getConstructor(new Class[]{int.class,int.class});
        move.invoke(con.newInstance(1,2),1,2);
	}
	
	public static void changeMethod2()throws Exception {
		ClassPool pool=ClassPool.getDefault();
        CtClass ct=pool.getCtClass("org.demo.Point");
        CtMethod m=ct.getDeclaredMethod("move");
        m.insertBefore("{ System.out.print(\"dx:\"+$1); System.out.println(\"dy:\"+$2);}");
        ct.writeFile("I:\\gitWorkspace\\demo\\demo\\javassit-demo\\target\\newClasses");
        //通过反射调用方法，查看结果
        Class pc=ct.toClass();
        Method move= pc.getMethod("move",new Class[]{int.class,int.class});
        Constructor<?> con=pc.getConstructor(new Class[]{int.class,int.class});
        move.invoke(con.newInstance(1,2),1,2);
	}

	public static void dynGenerateClass2() throws Exception {
		ClassPool pool = ClassPool.getDefault();
		CtClass ct = pool.makeClass("top.ss007.GenerateClass");// 创建类
		// 让类实现Cloneable接口
		ct.setInterfaces(new CtClass[] { pool.makeInterface("java.lang.Cloneable") });
		// 获得一个类型为int，名称为id的字段
		CtField f = new CtField(CtClass.intType, "id", ct);
		// 将字段设置为public
		f.setModifiers(AccessFlag.PUBLIC);
		ct.addField(f);// 将字段设置到类上
		// 添加构造函数
		CtConstructor constructor = CtNewConstructor.make("public GeneratedClass(int pId){this.id=pId;}", ct);
		ct.addConstructor(constructor);
		// 添加方法
		CtMethod helloM = CtNewMethod.make("public void hello(String des){ System.out.println(des);}", ct);
		ct.addMethod(helloM);
		// 将生成的.class文件保存到磁盘
		ct.writeFile("I:\\gitWorkspace\\demo\\demo\\javassit-demo\\target\\newClasses");
		// 下面的代码为验证代码
		Field[] fields = ct.toClass().getFields();
		System.out.println("属性名称：" + fields[0].getName() 
				+ "  属性类型：" + fields[0].getType());
	}
	public static void dynGenerateClass() {
		ClassPool pool = ClassPool.getDefault();
		CtClass ct = pool.makeClass("top.ss007.GenerateClass");// 创建类
		ct.setInterfaces(new CtClass[] { pool.makeInterface("java.lang.Cloneable") });// 让类实现Cloneable接口
		try {
			CtField f = new CtField(CtClass.intType, "id", ct);// 获得一个类型为int，名称为id的字段
			f.setModifiers(AccessFlag.PUBLIC);// 将字段设置为public
			ct.addField(f);// 将字段设置到类上
			// 添加构造函数
			CtConstructor constructor = CtNewConstructor.make("public GeneratedClass(int pId){this.id=pId;}", ct);
			ct.addConstructor(constructor);
			// 添加方法
			CtMethod helloM = CtNewMethod.make("public void hello(String des){ System.out.println(des);}", ct);
			ct.addMethod(helloM);
			// 将生成的.class文件保存到磁盘
			ct.writeFile("I:\\gitWorkspace\\demo\\demo\\javassit-demo\\target\\newClasses");
			// 下面的代码为验证代码
			Field[] fields = ct.toClass().getFields();
			System.out.println("属性名称：" + fields[0].getName() + "  属性类型：" + fields[0].getType());
		} catch (CannotCompileException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
